﻿using GuanQL.Core;
using GuanQL.Core.Domain.Accounts;
using GuanQL.Core.Multitenancy;
using GuanQL.Core.Stores;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using System;
using System.Linq;
using System.Security.Claims;
using ZhongJia.Core.Caching;

namespace GuanQL.Service
{
    public class WebContext : IWebContext
    {
        private readonly HttpContext _httpContext;
        private readonly ICacheClient _cacheClient;
        private readonly GQLDbContext _dbContext;
        private readonly ITenantResolver _tenantResolver;

        public WebContext(
            IHttpContextAccessor httpContextAccessor,
            ICacheClient cacheClient,
             GQLDbContext dbContext,
             ITenantResolver tenantResolver)
        {
            _cacheClient = cacheClient;
            _dbContext = dbContext;
            _httpContext = httpContextAccessor.HttpContext;
            _tenantResolver = tenantResolver;
        }

        private UserModel _cacheUser;
        private TenantModel _cacheTenant;

        public UserModel CurrentUser
        {
            get
            {
                if (!_httpContext.User.Identity.IsAuthenticated)
                    return null;

                if (_cacheUser != null)
                    return _cacheUser;

                var identity = _httpContext.User.Identity;
                var userName = _httpContext.User.Claims.First(c => c.Type == ClaimTypes.Name).Value;
                var tenantId = Guid.Parse(_httpContext.User.Claims.First(c => c.Type == ClaimTypes.UserData).Value);

                var user = _cacheClient.GetOrCreate($"User_{userName}_{tenantId}", async () =>
                {
                    return await _dbContext.Set<User>().Include(u => u.Roles).ThenInclude(r => r.Role).
                        FirstOrDefaultAsync(u => u.UserName == userName && u.TenantId == tenantId);
                },
                    TimeSpan.FromDays(1)).Result;

                if (user != null)
                {
                    _cacheUser = new UserModel(user);
                }
                else
                {
                    throw new UnauthorizedAccessException();
                }
                return _cacheUser;
            }
        }

        public bool IsLogin
        {
            get
            {
                return _httpContext.User.Identity.IsAuthenticated;
            }
        }

        public TenantModel CurrentTenant
        {
            get
            {
                if (_cacheTenant != null)
                    return _cacheTenant;

                _cacheTenant = _tenantResolver.GetTenant();
                return _cacheTenant;
            }
        }

        public Guid TenantId
        {
            get
            {
                if (IsLogin)
                {
                    return CurrentUser.TenantId;
                }
                else
                {
                    return CurrentTenant.TenantId;
                }
            }
        }

        public string ClientIpAddress
        {
            get
            {
                return _httpContext.Connection.RemoteIpAddress.ToString();
            }
        }
    }
}
